import asyncio
import logging
import os
import queue
import random
import re
import threading

import cv2
from PIL import Image, ImageDraw, ImageFilter, ImageFont
from aiogram import types
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import InputFile, ParseMode
from dateutil.relativedelta import relativedelta
from typing import List

import client
import client_kb
import handlers.users.generate.br_country as br_country
import sqlite_db
from common_utils import paste_watermark
from create_bot import BASE_DIR, bot, dp
from .br_utils import is_portuguese, pt_transliterate

logger = logging.getLogger(__name__)


def process_passport_photo(user_id):
    try:
        # Load the image and face detection classifier
        img = cv2.imread(
            f"./files/br_pass/br_dl/photo_usr/{user_id}.png", cv2.IMREAD_UNCHANGED
        )
        face_cascade = cv2.CascadeClassifier(
            f"./data/haarcascade_frontalface_default.xml"
        )

        # Detect faces in the image
        faces = face_cascade.detectMultiScale(img, 1.2, 5)

        # If faces are detected, crop and resize the image
        if len(faces) != 0:
            (x, y, w, h) = faces[0]
            h_top = int(h * 0.4)  # 0.4
            h_bottom = int(h * 0.3)  # 0.3
            w_left = int(w * 0.2)  # 0.2
            w_right = int(w * 0.2)  # 0.2
            x_left = max(0, x - w_left)
            x_right = min(img.shape[1], x + w + w_right)
            w_new = x_right - x_left
            y_top = max(0, y - h_top)
            y_bottom = min(img.shape[0], y + h + h_bottom)
            h_new = y_bottom - y_top

            cropped_img = img[y_top : y_top + h_new, x_left : x_left + w_new]
            cropped_img_pil = Image.fromarray(
                cv2.cvtColor(cropped_img, cv2.COLOR_BGRA2RGBA)
            )

            NewCrop = cropped_img_pil.resize((620, 690))
            # Save the processed image with the alpha channel
            NewCrop.save(f"./files/br_pass/br_dl/photo_usr/{user_id}_w.png")
            os.remove(f"./files/br_pass/br_dl/photo_usr/{user_id}.png")
        else:
            logger.error(f"No faces found in image for user_id {user_id}")
    except Exception as e:
        logger.error(f"Error processing passport photo for user_id {user_id}: {str(e)}")


def process_generate_signature(user_id, data):
    text = data.capitalize()
    if is_portuguese(text):
        text = pt_transliterate(text)
    txt = Image.new("RGBA", (1900, 600), (255, 255, 255, 0))
    go_txt = ImageDraw.Draw(txt)
    fnt1 = ImageFont.truetype(f"./fonts/1.ttf", size=270)
    go_txt.text(xy=(200, 50), text=f"{text}", font=fnt1, fill="#000000")
    fnt2 = ImageFont.truetype(f"./fonts/2.ttf", size=190)
    go_txt.text(xy=(800, 50), text=f"{text}", font=fnt2, fill="#000000", stroke_width=1)
    fnt3 = ImageFont.truetype(f"./fonts/3.ttf", size=200)
    go_txt.text(
        xy=(1400, 50), text=f"{text}", font=fnt3, fill="#000000", stroke_width=1
    )
    fnt4 = ImageFont.truetype(f"./fonts/4.ttf", size=100)
    go_txt.text(
        xy=(200, 400), text=f"{text}", font=fnt4, fill="#000000", stroke_width=1
    )
    fnt5 = ImageFont.truetype(f"./fonts/5.ttf", size=150)
    go_txt.text(
        xy=(800, 400), text=f"{text}", font=fnt5, fill="#000000", stroke_width=1
    )
    fnt6 = ImageFont.truetype(f"./fonts/6.ttf", size=80)
    go_txt.text(xy=(1400, 400), text=f"{text}", font=fnt6, fill="#000000")
    fnt66 = ImageFont.truetype(f"./fonts/66.ttf", size=80)
    go_txt.text(xy=(1430, 440), text=f"k", font=fnt66, fill="#000000")
    txt_blur = txt.filter(ImageFilter.GaussianBlur(radius=1))
    holst = Image.new("RGBA", (1900, 600), (255, 255, 255, 255))
    choose_signature = Image.alpha_composite(holst, txt_blur)
    choose_signature.save(
        f"./files/br_pass/br_dl/photo_usr/{user_id}_choose_signature.png"
    )


def create_keyboard(selected_categories: List[str]):
    """
    Функция генерирует клавиатуру с выбором категорий при запросе у пользователя.
    Состояние кнопок "с галочкой" или "без галочки" зависит от переданного массива уже выбранных категорий,
    который перед передачей в функцию запрашивается из State.
    :param selected_categories: List с выбранными категориями
    :return: объект types.InlineKeyboardMarkup
    """
    all_categories = ["A", "B", "AB"]

    kb = types.InlineKeyboardMarkup(row_width=4)
    for i in range(0, len(all_categories), 4):
        row = []
        for j in range(4):
            if i + j < len(all_categories):
                category = all_categories[i + j]
                if category in selected_categories:
                    text = f"{category} ✔️"
                else:
                    text = category
                row.append(
                    types.InlineKeyboardButton(
                        text=text, callback_data=f"cat_{category}"
                    )
                )
        kb.add(*row)
    next_field = types.InlineKeyboardButton(
        text="⏭️Далее", callback_data="cat_nextfield"
    )
    kb.add(back_button_inline, next_field)
    return kb


class FSM_DL(StatesGroup):
    dl_last_name = State()
    dl_first_name = State()
    dl_cpf_code = State()
    dl_father_name = State()
    dl_mother_name = State()
    dl_birth_date = State()
    dl_gave_city = State()
    dl_gave_organ = State()
    dl_photo = State()
    dl_signature_id = State()
    dl_category_select = State()
    dl_size = State()
    dl_edit_data = State()


back_kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
back_button = types.KeyboardButton(text="Назад ◀️")
back_button_inline = types.InlineKeyboardButton(
    text="Назад ◀️", callback_data="Назад ◀️"
)
back_kb.add(back_button)

data_fields = [
    {"title": "Имя", "key": "dl_first_name"},
    {"title": "Фамилия", "key": "dl_last_name"},
    {"title": "CPF-код лицензии", "key": "dl_cpf_code"},
    {"title": "ФИО отца", "key": "dl_father_name"},
    {"title": "ФИО матери", "key": "dl_mother_name"},
    {"title": "Дата рождения", "key": "dl_birth_date"},
    {"title": "Место выдачи", "key": "dl_gave_city"},
    {"title": "Орган выдавший лицензию", "key": "dl_gave_organ"},
    {"title": "Фотография", "key": "dl_photo"},
    {"title": "Подпись", "key": "dl_signature_id"},
    {"title": "Категории", "key": "dl_category_select"},
    {"title": "Размер документа", "key": "dl_size"},
]


async def data_checkup(user_id: int, state: FSMContext):
    try:
        data = await state.get_data()
        checkup_text = "Данные клиента:\n"
        for field in data_fields:
            if (
                field["key"] in data
                and data[field["key"]] != None
                and data[field["key"]] != []
            ):
                checkup_text += f"✅{field['title']}: {data[field['key']]}\n"
            else:
                checkup_text += f"{field['title']}:\n"
        if "message_to_edit_id" in data:
            await dp.bot.delete_message(
                chat_id=user_id, message_id=data["message_to_edit_id"]
            )
        return (await dp.bot.send_message(chat_id=user_id, text=checkup_text))[
            "message_id"
        ]
    except Exception as _ex:
        logger.exception(f"Ошибка в data_checkup: {_ex}")


async def delete_user_reply(user_id: int, message_id: int):
    try:
        await dp.bot.delete_message(chat_id=user_id, message_id=message_id)
    except Exception as e:
        logging.warning(f"Unable to delete user message: {e}")


@dp.message_handler(Text(equals="DL 🇧🇷"), state="*")
async def dl_first_name_input(message: types.Message, state: FSMContext):
    await state.update_data(dl_first_name=None)
    await dp.bot.send_photo(
        chat_id=message.from_user.id,
        photo=InputFile(f"./files/br_pass/br_dl/source/example.jpg"),
    )
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите имя✏️\n", parse_mode=ParseMode.HTML, reply_markup=back_kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_first_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_first_name
)
async def dl_first_name_validate(message: types.Message, state: FSMContext):
    dl_first_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")

    if re.match("^[A-Za-z `]+$", message.text) is not None or is_portuguese(
        str(message.text)
    ):
        dl_first_name = message.text
    if dl_first_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите имя в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл имя")
        await state.update_data(dl_first_name=dl_first_name.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_last_name_input(message, state)


async def dl_last_name_input(message: types.Message, state: FSMContext):
    logger.info(f"Пользователь {message.from_user.id} начал создание документа")
    await sqlite_db.sql_add_country_user(message.from_user.id, "br_dl")
    await state.update_data(type="dl")
    await state.update_data(dl_last_name=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите фамилию✏️\n", parse_mode=ParseMode.HTML, reply_markup=back_kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_last_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_last_name
)
async def dl_last_name_validate(message: types.Message, state: FSMContext):
    dl_last_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")

    if re.match("^[A-Za-z `]+$", message.text) is not None or is_portuguese(
        str(message.text)
    ):
        dl_last_name = message.text
    if dl_last_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите фамилию в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл фамилию")
        await state.update_data(dl_last_name=dl_last_name.upper())
        data["sign"] = dl_last_name.capitalize()
        if is_portuguese(data["sign"]):
            data["sign"] = pt_transliterate(data["sign"])
        if len(data["sign"]) > 5:
            data["sign"] = data["sign"][: random.randint(3, 5)]
        await state.update_data(sign=data["sign"])
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_cpf_code_input(message, state)


async def dl_cpf_code_input(message: types.Message, state: FSMContext):
    data = await state.get_data()
    await state.update_data(dl_cpf_code=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton(text="Сгенерировать"))
    kb.add(back_button)
    question_message_id = (
        await message.answer(
            "Введите идентификатор лицензии✏️\n"
            f"<i>Формат ввода: YYY.YYY.YYY-YY (11 цифр), Y – цифры.</i>\n",
            parse_mode=ParseMode.HTML,
            reply_markup=kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_cpf_code.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_cpf_code
)
async def dl_cpf_code_validate(message: types.Message, state: FSMContext):
    dl_cpf_code = None
    msg = message.text.upper().strip()
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")
    if message.text == "Сгенерировать":
        dl_cpf_code = f"{random.randrange(111,999)}.{random.randrange(111,999)}.{random.randrange(111,999)}-{random.randrange(11,99)}"
    elif re.match(r"^\d{3}.\d{3}.\d{3}-\d{2}$", msg):
        dl_cpf_code = msg
    if dl_cpf_code is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="Сгенерировать"))
        question_message_id = (
            await message.answer(
                text=f"❌Введите идентификатор лицензии в правильном формате.\n"
                f"<i>Формат ввода: YYY.YYY.YYY-YY (11 цифр), Y – цифры.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл идентификатор лицензии")
        await state.update_data(dl_cpf_code=dl_cpf_code.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_father_name_input(message, state)


async def dl_father_name_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(dl_father_name=None)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton("Пропустить"), back_button)
    question_message_id = (
        await message.answer(
            "Введите ФИО отца✏️\n", parse_mode=ParseMode.HTML, reply_markup=kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_father_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_father_name
)
async def dl_father_name_validate(message: types.Message, state: FSMContext):
    dl_father_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")

    if (
        re.match("^[A-Za-z `]+$", message.text) is not None
        or is_portuguese(str(message.text))
        or message.text == "Пропустить"
    ):
        dl_father_name = message.text
    if dl_father_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton("Пропустить"), back_button)
        question_message_id = (
            await message.answer(
                text="❌Введите ФИО отца в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл имя")
        await state.update_data(dl_father_name=dl_father_name.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_mother_name_input(message, state)


async def dl_mother_name_input(message: types.Message, state: FSMContext):
    await state.update_data(dl_mother_name=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите ФИО матери✏️\n", parse_mode=ParseMode.HTML, reply_markup=back_kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_mother_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_mother_name
)
async def dl_mother_name_validate(message: types.Message, state: FSMContext):
    dl_mother_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")

    if re.match("^[A-Za-z `]+$", message.text) is not None or is_portuguese(
        str(message.text)
    ):
        dl_mother_name = message.text
    if dl_mother_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите ФИО матери в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл имя")
        await state.update_data(dl_mother_name=dl_mother_name.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_birth_date_input(message, state)


async def dl_birth_date_input(message: types.Message, state: FSMContext):
    await state.update_data(dl_birth_date=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите дату рождения✏️\n" "<i>Формат ввода: дд.мм.гггг</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=back_kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_birth_date.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_birth_date
)
async def dl_birth_date_validate(message: types.Message, state: FSMContext):
    dl_birth_date = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")

    if re.match(r"^\d{2}\.\d{2}\.\d{4}$", message.text) is not None:
        dl_birth_date = message.text
    if dl_birth_date is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите дату рождения в правильном формате.\n"
                "<i>Формат ввода: DD.MM.YYY</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл дату рождения")
        await state.update_data(dl_birth_date=dl_birth_date)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_gave_city_input(message, state)


async def dl_gave_city_input(message: types.Message, state: FSMContext):
    await state.update_data(dl_gave_city=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kbOK = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kbOK.add(types.KeyboardButton(text="RECIFE, PE"))
    kbOK.add(types.KeyboardButton(text="SAO PAULO, SP"))
    kbOK.add(types.KeyboardButton(text="RIO DE JANEIRO, RJ"))
    kbOK.add(types.KeyboardButton(text="BELO HORIZONTE, MG"))
    kbOK.add(types.KeyboardButton(text="TERESINA, PI"))
    kbOK.add(back_button)
    question_message_id = (
        await message.answer(
            "Введите место выдачи✏️\n", parse_mode=ParseMode.HTML, reply_markup=kbOK
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_gave_city.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_gave_city
)
async def dl_gave_city_validate(message: types.Message, state: FSMContext):
    dl_gave_city = None
    msg = message.text
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")
    if (
        message.text == "RECIFE, PE"
        or message.text == "SAO PAULO, SP"
        or message.text == "RIO DE JANEIRO, RJ"
        or message.text == "BELO HORIZONTE, MG"
        or message.text == "TERESINA, PI"
    ):
        dl_gave_city = message.text
    if dl_gave_city is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="RECIFE, PE"))
        kb.add(types.KeyboardButton(text="SAO PAULO, SP"))
        kb.add(types.KeyboardButton(text="RIO DE JANEIRO, RJ"))
        kb.add(types.KeyboardButton(text="BELO HORIZONTE, MG"))
        kb.add(types.KeyboardButton(text="TERESINA, PI"))
        kb.add(back_button)
        question_message_id = (
            await message.answer(
                text=f"❌Введите место выдачи с помощью клавиатуры.\n",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл место выдачи.")
        await state.update_data(dl_gave_city=dl_gave_city.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_gave_organ_input(message, state)


async def dl_gave_organ_input(message: types.Message, state: FSMContext):
    await state.update_data(dl_gave_organ=None)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton(text="SDS"))
    kb.add(types.KeyboardButton(text="PC"))
    kb.add(types.KeyboardButton(text="SSP"))
    kb.add(types.KeyboardButton(text="SESP"))
    kb.add(back_button)
    question_message_id = (
        await message.answer(
            "Введите орган, выдавший лицензию, с помощью клавиатуры✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_gave_organ.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_gave_organ
)
async def dl_gave_organ_validate(message: types.Message, state: FSMContext):
    dl_gave_organ = None
    msg = message.text
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")
    if (
        message.text == "SDS"
        or message.text == "PC"
        or message.text == "SSP"
        or message.text == "SESP"
    ):
        dl_gave_organ = message.text
    if dl_gave_organ is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="SDS"))
        kb.add(types.KeyboardButton(text="PC"))
        kb.add(types.KeyboardButton(text="SSP"))
        kb.add(types.KeyboardButton(text="SESP"))
        kb.add(back_button)
        question_message_id = (
            await message.answer(
                text=f"❌Введите орган, выдавший права, с помощью клавиатуры.\n",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл место выдачи.")
        await state.update_data(dl_gave_organ=dl_gave_organ.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await dl_photo_input(message, state)


async def dl_photo_input(user_id: int or types.Message, state: FSMContext):
    await state.update_data(dl_photo=None)
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await dp.bot.send_message(
            chat_id=user_id,
            text="Загрузите фотографию 📷\n"
            " ❗️Требования к фотографии:\n"
            "➖ Фотография должна быть загружена без сжатия, нажимаем скрепку - файл - выбрать фото;\n"
            "➖ На фотографии должно быть видно плечи, глаза открыты;\n"
            "➖ Кадр должен быть в хорошем освещении;\n"
            "➖ Лицо должно быть под прямым углом к камере;\n"
            "Поддерживаемые форматы: JPG, JPEG, PNG ❗️",
            reply_markup=back_kb,
        )
    )["message_id"]
    await FSM_DL.dl_photo.set()
    await state.update_data(question_message_id=question_message_id)


@dp.message_handler(content_types=types.ContentType.DOCUMENT, state=FSM_DL.dl_photo)
async def process_dl_photo(message: types.Message, state: FSMContext):
    data = await state.get_data()
    file_info = await dp.bot.get_file(message.document.file_id)
    await message.delete()
    if file_info.file_path.lower().endswith(".png"):
        photo_path = f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.png"
        await dp.bot.download_file(file_info.file_path, photo_path)
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            while thread.is_alive():
                await asyncio.sleep(1)
            processed_photo_path = (
                f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await state.update_data(message_to_edit_id=message_to_edit_id)
                except:
                    pass
                await state.update_data(dl_photo="Есть")
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await dl_signature_id_input(message, state)
    elif file_info.file_path.lower().endswith(".jpg"):
        photo_path = f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.png"
        await dp.bot.download_file(
            file_info.file_path,
            f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.jpg",
        )
        # AI work

        from rembg import remove

        out = remove(
            Image.open(f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.jpg"),
            True,
            240,
            240,
        )
        out = out.convert("RGBA")
        out.save(f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.png")
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            while thread.is_alive():
                await asyncio.sleep(1)
            processed_photo_path = (
                f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await state.update_data(message_to_edit_id=message_to_edit_id)
                except:
                    pass
                await state.update_data(dl_photo="Есть")
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await dl_signature_id_input(message, state)
    elif file_info.file_path.lower().endswith(".jpeg"):
        photo_path = f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.png"
        await dp.bot.download_file(
            file_info.file_path,
            f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.jpeg",
        )
        # AI work

        from rembg import remove

        out = remove(
            Image.open(f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.jpeg"),
            True,
            240,
            240,
        )
        out = out.convert("RGBA")
        out.save(f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}.png")
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            while thread.is_alive():
                await asyncio.sleep(1)
            processed_photo_path = (
                f"./files/br_pass/br_dl/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await state.update_data(message_to_edit_id=message_to_edit_id)
                except:
                    pass
                await state.update_data(dl_photo="Есть")
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await dl_signature_id_input(message, state)
            else:
                await dp.bot.send_message(
                    chat_id=message.chat.id,
                    text="❌ Фотография не соответствует требованиям.\n"
                    "ИИ не смог обработать вашу фотографию.\n"
                    "Это происходит, если фото не соответствует требованиям, "
                    "проверьте что расширение файла PNG, "
                    "либо загрузите другое изображение.",
                )
        else:
            await dp.bot.send_message(
                chat_id=message.chat.id,
                text="❌ Фотография не соответствует требованиям.\n"
                "ИИ не смог обработать вашу фотографию.\n"
                "Это происходит, если фото не соответствует требованиям, "
                "проверьте что расширение файла PNG, "
                "либо загрузите другое изображение.",
            )
    else:
        await dp.bot.send_message(
            chat_id=message.chat.id,
            text="❌ Фотография не соответствует требованиям.\n"
            "ИИ не смог обработать вашу фотографию.\n"
            "Это происходит, если фото не соответствует требованиям, "
            "проверьте что расширение файла PNG, "
            "либо загрузите другое изображение.",
        )


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_photo
)
async def process_dl_photo_nontype(message: types.Message, state: FSMContext):
    await message.delete()
    await message.answer(
        "Вы должны отправить фотографию без фона в формате PNG и без сжатия."
    )


@dp.message_handler(content_types=types.ContentType.PHOTO, state=FSM_DL.dl_photo)
async def process_dl_photo_nontype_photo(message: types.Message, state: FSMContext):
    await message.delete()
    await message.answer(
        "Вы должны отправить фотографию без фона в формате PNG и без сжатия."
    )


async def dl_signature_id_input(user_id, state: FSMContext):
    await state.update_data(dl_signature_id=None)
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    data = await state.get_data()

    process_generate_signature(user_id=user_id, data=data["sign"])

    kb = types.InlineKeyboardMarkup()
    kb.add(
        types.InlineKeyboardButton(text="1", callback_data="sig_1"),
        types.InlineKeyboardButton(text="2", callback_data="sig_2"),
        types.InlineKeyboardButton(text="3", callback_data="sig_3"),
    )
    kb.add(
        types.InlineKeyboardButton(text="4", callback_data="sig_4"),
        types.InlineKeyboardButton(text="5", callback_data="sig_5"),
        types.InlineKeyboardButton(text="6", callback_data="sig_6"),
    )
    kb.add(
        types.InlineKeyboardButton(text="Не ставить", callback_data="sig_0"),
        back_button_inline,
    )

    photo_path = f"./files/br_pass/br_dl/photo_usr/{user_id}_choose_signature.png"  # Замените на путь к вашей картинке
    with open(photo_path, "rb") as photo:
        question_message_id = (
            await dp.bot.send_photo(
                chat_id=user_id,
                photo=photo,
                caption="Выберите тип подписи:",
                reply_markup=kb,
            )
        )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_DL.dl_signature_id.set()


@dp.callback_query_handler(
    lambda c: c.data.startswith("sig_") and "Назад ◀️" not in c.data,
    state=FSM_DL.dl_signature_id,
)
async def dl_signature_id_validate(
    callback_query: types.CallbackQuery, state: FSMContext
):
    await dp.bot.answer_callback_query(callback_query.id)
    signature_id = int(callback_query.data.split("_")[1])
    await state.update_data(dl_signature_id=signature_id)
    logger.info(f"Пользователь {callback_query.from_user.id} выбрал подпись")
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=callback_query.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")
    if "edit_mode" in data:
        return await start_generate_edit(callback_query.from_user.id, state)
    message_to_edit_id = await data_checkup(callback_query.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await dl_category_select_input(callback_query.from_user.id, state)


async def dl_category_select_input(user_id: int or types.Message, state: FSMContext):
    await state.update_data(dl_category_select=[])
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    data = await state.get_data()
    selected_categories = data.get("dl_category_select", [])
    await dp.bot.send_message(
        chat_id=user_id,
        text="Выберите категории:",
        reply_markup=create_keyboard(selected_categories),
    )
    await FSM_DL.dl_category_select.set()


@dp.callback_query_handler(
    lambda c: c.data.startswith("cat_"), state=FSM_DL.dl_category_select
)
async def process_category_select(
    callback_query: types.CallbackQuery, state: FSMContext
):
    category = callback_query.data.split("_")[1]
    data = await state.get_data()
    if category == "nextfield":
        await dp.bot.delete_message(
            chat_id=callback_query.from_user.id,
            message_id=callback_query.message.message_id,
        )
        if "edit_mode" in data:
            return await start_generate_edit(callback_query.from_user.id, state)
        return await dl_size_input(callback_query.from_user.id, state)
    await dp.bot.answer_callback_query(callback_query.id)
    selected_categories = data.get("dl_category_select", [])
    if category in selected_categories:
        selected_categories.remove(category)
    else:
        selected_categories.append(category)
    await state.update_data(dl_category_select=selected_categories)
    await dp.bot.edit_message_reply_markup(
        chat_id=callback_query.from_user.id,
        message_id=callback_query.message.message_id,
        reply_markup=create_keyboard(selected_categories),
    )


async def dl_size_input(user_id: int or types.Message, state: FSMContext):
    await state.update_data(size=None)
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
    kb.add(types.KeyboardButton(text="📃На листе А4"))
    kb.add(types.KeyboardButton(text="🪪В размер документа"))
    kb.add(back_button)
    question_message_id = (
        await dp.bot.send_message(
            chat_id=user_id, text="Выберите размер документа", reply_markup=kb
        )
    )["message_id"]
    await FSM_DL.dl_size.set()
    await state.update_data(question_message_id=question_message_id)


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_DL.dl_size
)
async def dl_select_size_validate(message: types.Message, state: FSMContext):
    if message.text == "📃На листе А4":
        size_type = "A4"
    elif message.text == "🪪В размер документа":
        size_type = "DOC"
    else:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="📃На листе А4"))
        kb.add(types.KeyboardButton(text="🪪В размер документа"))
        kb.add(back_button)
        question_message_id = (
            await message.answer(
                text="❌Выберите тип через клавиатуру.\n",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        return await state.update_data(question_message_id=question_message_id)
    await message.delete()
    await state.update_data(size=size_type)
    logger.info(f"Пользователь {message.from_user.id} выбрал размер документа")
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logging.warning("question_message_id not found in state data")
    if "edit_mode" in data:
        return await start_generate_edit(message.from_user.id, state)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await start_generate(message, state)


async def start_generate(message: types.Message, state: FSMContext):
    message_to_delete = await message.answer("Ожидайте генерируется...")
    await dp.bot.send_chat_action(message.chat.id, "upload_photo")
    await state.update_data(progress_message_id=message_to_delete["message_id"])
    data = await state.get_data()
    await dp.bot.delete_message(
        chat_id=message.from_user.id, message_id=data["message_to_edit_id"]
    )
    logger.info(f"Начинаем генерацию документа для пользователя {message.from_user.id}")
    result_queue = queue.Queue()
    id_thread = threading.Thread(
        target=generate_dl, args=(data, message.from_user.id, result_queue)
    )
    id_thread.start()
    await dp.bot.send_chat_action(message.chat.id, "upload_photo")
    id_thread.join()
    result = result_queue.get()
    if "Error" in result:
        logger.error(
            f"Ошибка при генерации документа для пользователя {message.from_user.id}:\n{result}"
        )
        await message.answer("❌Ошибка при генерации изображения")
        await dp.bot.send_message(chat_id=message.from_user.id, text=result)
    else:
        logger.info(
            f"Успешно завершили генерацию документа для пользователя {message.from_user.id}"
        )
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=message_to_delete["message_id"]
        )
        with open(result + "_wm.png", "rb") as photo:
            await dp.bot.send_document(chat_id=message.from_user.id, document=photo)
            await message.answer(
                "Завершите покупку документа.", reply_markup=client_kb.kb_br_finish_dl
            )


async def start_generate_edit(user_id: int, state: FSMContext):
    message_to_delete = await dp.bot.send_message(
        chat_id=user_id, text="Ожидайте генерируется..."
    )
    await dp.bot.send_chat_action(user_id, "upload_photo")
    await state.update_data(progress_message_id=message_to_delete["message_id"])
    data = await state.get_data()
    result_queue = queue.Queue()
    id_thread = threading.Thread(target=generate_dl, args=(data, user_id, result_queue))
    id_thread.start()
    await dp.bot.send_chat_action(user_id, "upload_photo")
    id_thread.join()
    result = result_queue.get()
    if "Error" in result:
        await dp.bot.send_message(
            chat_id=user_id, text="❌Ошибка при генерации изображения"
        )
    else:
        await dp.bot.delete_message(
            chat_id=user_id, message_id=message_to_delete["message_id"]
        )
        with open(result + "_wm.png", "rb") as photo:
            await dp.bot.send_document(chat_id=user_id, document=photo)
            await dp.bot.send_message(
                chat_id=user_id,
                text="Завершите покупку документа.",
                reply_markup=client_kb.kb_br_finish_dl,
            )


@dp.callback_query_handler(text="br_change_dl", state="*")
async def br_change_dl(call: types.CallbackQuery, state: FSMContext):
    kbS = types.ReplyKeyboardMarkup(one_time_keyboard=True)
    await call.message.delete()
    for field in data_fields:
        kbS.add(types.KeyboardButton(text=f'{field["title"]}'))
    edit_message_to_delete_id = (
        await call.message.answer(
            text="Выберите параметр, который хотите изменить", reply_markup=kbS
        )
    )["message_id"]
    await state.update_data(edit_message_to_delete_id=edit_message_to_delete_id)
    await FSM_DL.dl_edit_data.set()


@dp.message_handler(state=FSM_DL.dl_edit_data)
async def edit_field(message: types.Message, state: FSMContext):
    data = await state.get_data()
    await dp.bot.delete_message(
        chat_id=message.from_user.id, message_id=int(data["edit_message_to_delete_id"])
    )
    await message.delete()
    for field in data_fields:
        if field["title"] == message.text:
            key = field["key"]
    await state.update_data(edit_mode=1)
    func_name = key
    func_name_with_input = func_name + "_input"

    # Получаем ссылку на функцию с использованием имени и вызываем ее
    function_to_call = globals()[func_name_with_input]
    await function_to_call(message, state)

    dl_last_name = State()
    dl_first_name = State()
    dl_cpf_code = State()
    dl_father_name = State()
    dl_mother_name = State()
    dl_birth_date = State()
    dl_gave_city = State()
    dl_gave_organ = State()
    dl_photo = State()
    dl_signature_id = State()
    dl_category_select = State()
    dl_size = State()
    dl_edit_data = State()


state_input_functions = {
    "FSM_DL:dl_last_name": dl_first_name_input,
    "FSM_DL:dl_cpf_code": dl_last_name_input,
    "FSM_DL:dl_father_name": dl_cpf_code_input,
    "FSM_DL:dl_mother_name": dl_father_name_input,
    "FSM_DL:dl_birth_date": dl_mother_name_input,
    "FSM_DL:dl_gave_city": dl_birth_date_input,
    "FSM_DL:dl_gave_organ": dl_gave_city_input,
    "FSM_DL:dl_photo": dl_gave_organ_input,
    "FSM_DL:dl_signature_id": dl_photo_input,
    "FSM_DL:dl_category_select": dl_signature_id_input,
    "FSM_DL:dl_serial_number": dl_category_select_input,
}


async def command_create_br(message: types.Message):
    user_id = message.from_user.id
    await sqlite_db.sql_check_user(user_id)
    await bot.send_message(
        user_id, "Выберите документ для создания", reply_markup=client_kb.kb_br
    )
    await br_country.FSM.create_br_pass.set()


@dp.message_handler(lambda message: message.text == "Назад ◀️", state=FSM_DL)
async def go_back(message: types.Message, state: FSMContext):
    current_state = str(await state.get_state())
    logger.info(
        f"Пользователь {message.from_user.username} вернулся назад с поля {current_state}"
    )
    if current_state == "FSM_DL:dl_first_name":
        await command_create_br(message)
    if current_state == "FSM_DL:dl_size":
        await dl_category_select_input(message, state)
    elif current_state in state_input_functions:
        input_function = state_input_functions[current_state]
        await input_function(
            message, state
        )  # вызов функции ввода для предыдущего состояния
    else:
        await message.answer("Unknown state.")


@dp.callback_query_handler(lambda call: call.data == "Назад ◀️", state="*")
async def go_back(call: types.CallbackQuery, state: FSMContext):
    await call.message.delete()
    current_state = str(await state.get_state())
    logger.info(
        f"Пользователь {call.from_user.username} вернулся назад с поля {current_state}"
    )
    if current_state == "FSM_DL:dl_signature_id":
        await dl_photo_input(call.from_user.id, state)
    elif current_state == "FSM_DL:dl_category_select":
        await dl_signature_id_input(call.from_user.id, state)
    elif current_state in state_input_functions:
        input_function = state_input_functions[current_state]
        await input_function(
            call.message, state
        )  # вызов функции ввода для предыдущего состояния
    else:
        await call.message.answer("Unknown state.")


@dp.callback_query_handler(text="br_pay_dl", state="*")
async def command_pay_br_dl(callback: types.CallbackQuery, state: FSMContext):
    await state.finish()
    await state.update_data(pay_country="br_dl")
    await client.command_promo_quest(callback, state)


def generate_dl(data, user_id, result_queue):
    try:
        import datetime
        import random

        import codicefiscale as codicefiscale
        from mrz.generator.td1 import TD1CodeGenerator
        from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont

        image = Image.open(f"./files/br_pass/br_dl/source/front.png").convert("RGBA")
        draw = ImageDraw.Draw(image)

        # ИМЯ И ФАМИЛИЯ

        first_name = data.get("dl_first_name", "")  # 1
        last_name = data.get("dl_last_name", "")  # 2

        text_image = Image.new("RGBA", image.size, (255, 255, 255, 0))
        font = ImageFont.truetype(f"./fonts/Brazil_Courier New.ttf", 60)
        x, y = 335, 420
        draw.text(
            xy=(x, y),
            text=str(first_name + " " + last_name),
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        # Серия лицензии

        serial_DL = str(random.randrange(1111111111, 9999999999))

        tim = Image.new("RGBA", (1400, 1400), (0, 0, 0, 0))
        dr = ImageDraw.Draw(tim)
        ft = ImageFont.truetype("./fonts/Brazil_PASS_SERIF.otf", 109)
        dr.text((45, 160), serial_DL, font=ft, fill=(68, 63, 49))
        tim = tim.rotate(90)
        image.paste(tim, (0, 0), tim)

        tim1 = Image.new("RGBA", (2750, 2750), (0, 0, 0, 0))
        dr1 = ImageDraw.Draw(tim1)
        ft = ImageFont.truetype("./fonts/Brazil_PASS_SERIF.otf", 109)
        dr1.text((0, 120), serial_DL, font=ft, fill=(68, 63, 49))
        tim1 = tim1.rotate(90)
        image.paste(tim1, (0, 0), tim1)

        # Данные - 2 строка

        gave_organ = data.get("dl_gave_organ", "")
        gave_city = data.get("dl_gave_city", "")
        print(gave_city, gave_organ)

        draw.text(
            xy=(1020, 565),
            text=(
                str(random.randrange(11111111, 99999999))
                + "  "
                + gave_organ
                + "  "
                + gave_city.split()[-1]
            ),
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        # Данные 3 строка
        cpf_code = data.get("dl_cpf_code", "")
        date_birth = data.get("dl_birth_date", "")
        draw.text(
            xy=(1000, 700),
            text=cpf_code,
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        draw.text(
            xy=(1570, 700),
            text=(date_birth.replace(".", "/")),
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        # ФИО отца и матери

        father_name = data.get("dl_father_name", "")
        mother_name = data.get("dl_mother_name", "")

        from textwrap import fill

        if str(father_name).capitalize() != "Пропустить":
            if len(str(father_name)) >= 25:
                draw.text(
                    xy=(1010, 850),
                    text=str(fill(father_name, width=25).split("\n")[0]),
                    font=font,
                    fill=(12, 12, 12, 200),
                    stroke_width=0,
                    anchor="lm",
                )
                draw.text(
                    xy=(1010, 910),
                    text=str(fill(father_name, width=25).split("\n")[1]),
                    font=font,
                    fill=(12, 12, 12, 200),
                    stroke_width=0,
                    anchor="lm",
                )
            else:
                draw.text(
                    xy=(1010, 850),
                    text=father_name,
                    font=font,
                    fill=(12, 12, 12, 200),
                    stroke_width=0,
                    anchor="lm",
                )
        else:
            draw.text(
                xy=(1010, 850),
                text=" ",
                font=font,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )

        if len(str(mother_name)) >= 25:
            draw.text(
                xy=(1010, 980),
                text=str(fill(mother_name, width=25).split("\n")[0]),
                font=font,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
            draw.text(
                xy=(1010, 1040),
                text=str(fill(mother_name, width=25).split("\n")[1]),
                font=font,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
        else:
            draw.text(
                xy=(1010, 980),
                text=mother_name,
                font=font,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )

        # категории

        category = data.get("dl_category_select", "")
        cft = ImageFont.truetype("./fonts/Brazil_Courier New.ttf", 60)

        if len(category) == 1:
            draw.text(
                xy=(1785, 1215),
                text=category[0],
                font=cft,
                fill=(163, 83, 68),
                stroke_width=0,
                anchor="lm",
            )
        elif len(category) == 2:
            draw.text(
                xy=(1750, 1215),
                text=str(category[0] + " " + category[1]),
                font=cft,
                fill=(163, 83, 68),
                stroke_width=0,
                anchor="lm",
            )
        elif len(category) == 3:
            draw.text(
                xy=(1720, 1215),
                text=str(category[0] + " " + category[1] + " " + category[2]),
                font=cft,
                fill=(163, 83, 68),
                stroke_width=0,
                anchor="lm",
            )

        ft_reg_num = ImageFont.truetype("./fonts/Brazil_Courier New.ttf", 65)
        draw.text(
            xy=(405, 1350),
            text=str(random.randrange(11111111111, 99999999999)),
            font=ft_reg_num,
            fill=(163, 83, 68),
            stroke_width=0,
            anchor="lm",
        )

        date_birth = data.get("dl_birth_date", "")

        date_gave = datetime.datetime.strptime("01.01.2018", "%d.%m.%Y").date()
        date_gave = date_gave + relativedelta(years=random.randrange(1, 3))
        date_gave = date_gave + relativedelta(months=random.randrange(2, 7))
        date_gave = date_gave + relativedelta(days=random.randrange(6, 16))

        draw.text(
            xy=(1500, 1350),
            text=date_gave.strftime("%d/%m/%Y"),
            font=ft_reg_num,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        enemy_date = date_gave + relativedelta(
            years=random.randrange(1, 2),
            months=random.randrange(1, 2),
            days=random.randrange(1, 4),
        )

        cft1 = ImageFont.truetype("./fonts/Brazil_Courier New.ttf", 60)
        draw.text(
            xy=(1520, 2358),
            text=enemy_date.strftime("%d/%m/%Y"),
            font=cft1,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        draw.text(
            xy=(1005, 1350),
            text=(enemy_date + relativedelta(years=random.randrange(4, 5))).strftime(
                "%d/%m/%Y"
            ),
            font=cft1,
            fill=(163, 83, 68),
            stroke_width=0,
            anchor="lm",
        )

        draw.text(
            xy=(355, 2360),
            text=gave_city,
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        arial = ImageFont.truetype("./fonts/Brazil_Arial.TTF", 60)

        draw.text(
            xy=(1498, 2580),
            text=str(random.randrange(11111111111, 99999999999)),
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        draw.text(
            xy=(1498, 2630),
            text=str(gave_city).split()[-1]
            + str(random.randrange(111111111, 999999999)),
            font=font,
            fill=(12, 12, 12, 200),
            stroke_width=0,
            anchor="lm",
        )

        if gave_city == "RECIFE, PE":
            im = Image.open(f"./files/br_pass/br_dl/source/PE.png").convert("RGBA")
            image.paste(im, (1567, 0), im)
            draw.text(
                xy=(830, 2680),
                text="PERNAMBUCO",
                font=arial,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
        elif gave_city == "SAO PAULO, SP":
            im = Image.open(f"./files/br_pass/br_dl/source/SP.png").convert("RGBA")
            image.paste(im, (1567, 0), im)
            draw.text(
                xy=(880, 2680),
                text="SAO PAULO",
                font=arial,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
        elif gave_city == "RIO DE JANEIRO, RJ":
            im = Image.open(f"./files/br_pass/br_dl/source/RJ.png").convert("RGBA")
            image.paste(im, (1520, 0), im)
            draw.text(
                xy=(830, 2680),
                text="RIO DE JANEIRO",
                font=arial,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
        elif gave_city == "BELO HORIZONTE, MG":
            im = Image.open(f"./files/br_pass/br_dl/source/MG.png").convert("RGBA")
            image.paste(im, (1567, 0), im)
            draw.text(
                xy=(830, 2680),
                text="MINAS GERAIS",
                font=arial,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )
        elif gave_city == "TERESINA, PI":
            im = Image.open(f"./files/br_pass/br_dl/source/PI.png").convert("RGBA")
            image.paste(im, (1567, 0), im)
            draw.text(
                xy=(960, 2680),
                text="PIAUI",
                font=arial,
                fill=(12, 12, 12, 200),
                stroke_width=0,
                anchor="lm",
            )

        signature_id = data.get("dl_signature_id", 4)
        from .br_utils import pt_transliterate

        sign = data["sign"].capitalize()
        if is_portuguese(sign):
            sign = pt_transliterate(sign)
        if signature_id != 0:
            fonts_dict = {
                1: ImageFont.truetype(f"{BASE_DIR}/fonts/1.ttf", size=300),
                2: ImageFont.truetype(f"{BASE_DIR}/fonts/2.ttf", size=190),
                3: ImageFont.truetype(f"{BASE_DIR}/fonts/3.ttf", size=250),
                4: ImageFont.truetype(f"{BASE_DIR}/fonts/4.ttf", size=170),
                5: ImageFont.truetype(f"{BASE_DIR}/fonts/5.ttf", size=220),
                6: ImageFont.truetype(f"{BASE_DIR}/fonts/6.ttf", size=160),
                7: ImageFont.truetype(f"{BASE_DIR}/fonts/66.ttf", size=90),
            }
            from .br_utils import pt_transliterate

            if signature_id == 6:
                font = fonts_dict[5]
                x, y = 910 - (font.getbbox(sign)[2] - font.getbbox(sign)[0]) // 2, 2110
                txt = Image.new("RGBA", image.size, (255, 255, 255, 0))
                go_txt = ImageDraw.Draw(txt)
                go_txt.text(
                    xy=(x, y),
                    text=pt_transliterate(sign),
                    font=font,
                    fill=(29, 29, 29, 255),
                    stroke_width=0,
                    anchor="lm",
                )
                go_txt.text(
                    xy=(x + 50, y - 15),
                    text=f"k",
                    font=fonts_dict[7],
                    fill=(29, 29, 29, 255),
                )
                txt_blur = txt.filter(ImageFilter.GaussianBlur(radius=0.5))
                # Создайте новый слой подписи с размером, соответствующим изображению документа
                signature_layer = Image.new("RGBA", image.size, (255, 255, 255, 0))

                # Вставьте изображение подписи на слой подписи
                signature_position = (0, 0)  # координаты x, y для вставки подписи
                signature_layer.paste(txt_blur, signature_position)

                # Объедините изображение документа и слой подписи
                image = Image.alpha_composite(image, signature_layer)
            else:
                font = fonts_dict[signature_id]
                x, y = 910 - (font.getbbox(sign)[2] - font.getbbox(sign)[0]) // 2, 2110
                txt = Image.new("RGBA", image.size, (255, 255, 255, 0))
                go_txt = ImageDraw.Draw(txt)
                go_txt.text(
                    xy=(x, y),
                    text=pt_transliterate(sign),
                    font=font,
                    fill=(29, 29, 29, 255),
                    stroke_width=0,
                    anchor="lm",
                )
                txt_blur = txt.filter(ImageFilter.GaussianBlur(radius=0.9))
                # Создайте новый слой подписи с размером, соответствующим изображению документа
                signature_layer = Image.new("RGBA", image.size, (255, 255, 255, 0))

                # Вставьте изображение подписи на слой подписи
                signature_position = (0, 30)  # координаты x, y для вставки подписи
                signature_layer.paste(txt_blur, signature_position)

                # Объедините изображение документа и слой подписи
                image = Image.alpha_composite(image, signature_layer)

        def multiply_images(image1, image2):
            result_image = Image.new("RGBA", image1.size, (0, 0, 0, 0))
            for x in range(image1.width):
                for y in range(image1.height):
                    pixel1 = image1.getpixel((x, y))
                    pixel2 = image2.getpixel((x, y))
                    new_pixel = tuple(int(a * b / 255) for a, b in zip(pixel1, pixel2))
                    result_image.putpixel((x, y), new_pixel)

            return result_image

        overlay_image = Image.open(
            f"./files/br_pass/br_dl/photo_usr/{user_id}_w.png"
        ).convert("RGBA")

        overlay_position = (
            310,
            570,
        )  # координаты x, y для вставки обрезанного изображения
        overlay_layer = Image.new("RGBA", image.size, (255, 255, 255, 0))
        overlay_layer.paste(overlay_image, overlay_position, overlay_image)

        # Используйте функцию multiply_images() для наложения overlay_image на image
        overlay_layer = multiply_images(image, overlay_layer)
        overlay_layer = overlay_layer.filter(ImageFilter.GaussianBlur(radius=0.9))
        # Объедините исходное изображение и новый слой с помощью `Image.alpha_composite()`
        image = Image.alpha_composite(image, overlay_layer)
        front = image  # промежуточное сохранение первой стороны. потом будем наклыдывать две стороны на пустой фон

        back = image
        image_name = f"./files/br_pass/br_dl/photo_usr/{user_id}_completed"
        if data["size"] == "DOC":
            # Сохранение полученного результата
            image.save(f"./files/br_pass/br_dl/photo_usr/{user_id}_completed.png")

            # Генерация версии в водяным знаком
        elif data["size"] == "A4":
            gap = 50
            # Создание нового изображения с нужными размерами
            image = Image.new(
                "RGBA",
                (front.width + back.width + gap, front.height),
                (255, 255, 255, 255),
            )

            # Вставка изображений в новое изображение
            image.alpha_composite(front, (0, 0))
            # Задаем размеры A4 в миллиметрах
            width_mm = 210
            height_mm = 297

            # Задаем разрешение изображения в DPI
            resolution_dpi = 600

            # Конвертируем размеры A4 в пиксели
            width_px = int(width_mm * resolution_dpi / 25.4)
            height_px = int(height_mm * resolution_dpi / 25.4)

            # Создаем новое изображение размером A4 с белым фоном
            image_a4 = Image.new("RGBA", (width_px, height_px), "white")
            new_width = 4100  # Задаем новую ширину в пикселях
            new_height = int(
                image.height * new_width / image.width
            )  # Вычисляем новую высоту, сохраняя соотношение сторон
            image = image.resize((new_width, new_height), Image.ANTIALIAS)
            image_a4.paste(image, (350, 350))

            # Сохраняем изображение в файл
            image_a4.save(image_name + ".png", "PNG")
        else:
            raise ValueError
        paste_watermark(
            f"./files/br_pass/br_dl/photo_usr/{user_id}_completed.png",
            f"./files/br_pass/br_dl/photo_usr/{user_id}_completed_wm.png",
        )
        result_queue.put(image_name)
    except KeyError as _ex:
        logger.error(_ex)
        result_queue.put(f"Error:Ошибка в предоставленных данных:\n")
    except ValueError as _ex:
        logger.error(_ex)
        result_queue.put(f"Error:Ошибка при сохранении результата:\n")
    except Exception as _ex:
        logger.error(_ex)
        result_queue.put(f"Error:Ошибка при генерации:\n")

    except Exception as e:
        print(e)
